#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__

#include<iostream>
#include<string>
#include<memory>
#include<cstring>
#include<cerrno>
#include<strings.h>   // bzero
#include<functional>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> // 网络通信
#include <arpa/inet.h>

#include"Log.hpp"
#include"Common.hpp"
#include"InetAddr.hpp"
#include"Threadpool.hpp"

using namespace LogModule;
using namespace ThreadPoolMudule;


const static int gsockfd = -1;
//const static std::string gdefaultip = "127.0.0.1"; // 表示本地主机
const static uint16_t gdefaultport = 8080;

using adduser_t = std::function<void(InetAddr& id)>;  // 新增用户
using remove_t = std::function<void(InetAddr& id)>;   // 移除用户

using route_t = std::function<void(int sockfd,const std::string& message)>; // 转发消息
using task_t = std::function<void()>;  // 给线程池的任务

class UdpServer
{
public:
	UdpServer(uint16_t port = gdefaultport)
	:_sockfd(gsockfd)
	,_addr(port)
	,_isrunning(false)
	{}

	void InitServer()  // 初始化服务器
	{
		// 1.创建套接字

		// int socket(int domain,int type,int protocol) domain 域/协议家族

		_sockfd = ::socket(AF_INET,SOCK_DGRAM,0);
		if(_sockfd < 0)
		{
			LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
			Die(SOCKET_ERR);
		}
		LOG(LogLevel::INFO) << "socket success,sockfd is: " << _sockfd;

		// 2 bind:设置进入内核
		int n = ::bind(_sockfd,_addr.NetAddr(),_addr.NetAddrLen());
		if(n < 0)
		{
			LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
			Die(BIND_ERR);
		}
		LOG(LogLevel::INFO) << "bind success";
	}  

	// 注册服务
	void RegisterService(adduser_t adduser,route_t route,remove_t removeuser)  //注册服务
	{
		_adduser = adduser;
		_route = route;
		_removeuser = removeuser;
	}

	void Start()
	{
		_isrunning = true;
		while(1)
		{
			char inbuffer[1024];
			struct sockaddr_in peer;
			socklen_t len = sizeof(peer);

			// 接收数据报
			ssize_t n = ::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);  // 标志位0表示阻塞
			if(n > 0) // 成功
			{
				// 1.消息内容  &&   2.谁给我发的
				// uint16_t clientport = ::ntohs(peer.sin_port);      // 网络序列转主机序列
				// std::string clientip = ::inet_ntoa(peer.sin_addr); // 网络序列转主机序列，字符串风格的

				InetAddr client(peer);
				inbuffer[n] = 0;      // 清空缓冲区
				std::string message;
				if(strcmp(inbuffer,"QUIT") == 0)
				{
					// 移除观察者
					_removeuser(client);
					message = client.Addr() + "# " + "我走了，你们聊";
				}
				else
				{
					// 2.新增用户
					_adduser(client);
					std::string message = client.Addr() + "# " + inbuffer; // 携带用户信息的消息
				}				

				// 3.构建转发任务，推送给线程池，让线程池进行转发
				task_t task = std::bind(UdpServer::_route,_sockfd,message);
				ThreadPool<task_t>::getInstance()->Equeue(task);

				std::string clientinfo = client.Ip() + ":" + std::to_string(client.Port()) + "# " + inbuffer;

				LOG(LogLevel::DEBUG)<< clientinfo;
			
				std::string echo_string = "echo#";
				echo_string += inbuffer;
				
				// 发消息
				::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),sizeof(peer));
			}
		}
		_isrunning = false;
	}
	~UdpServer()
	{
		if(_sockfd > gsockfd)
			::close(_sockfd);
	}
private:
	int _sockfd;    // 既可以发，也可以收---全双工
	InetAddr _addr; 
	bool _isrunning;// 服务器运行状态
	remove_t _removeuser;// 移除用户方法
	adduser_t _adduser; // 新增用户方法
	route_t _route;     // 路由转发功能
};









#endif